/*
 * Copyright 2007. Mount Sinai Hospital, Toronto, Canada.
 * 
 * Licensed under the GNU Lesser General Public License, Version 2. You
 * can find a copy of the license at:
 * 
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
 * 
 * IN NO EVENT SHALL MOUNT SINAI HOSPITAL BE LIABLE TO ANY PARTY FOR DIRECT, 
 * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST 
 * PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, 
 * EVEN IF MOUNT SINAI HOSPITAL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 
 * DAMAGE.
 * 
 * MOUNT SINAI HOSPITAL SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND 
 * ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". 
 * MOUNT SINAI HOSPITAL HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, 
 * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 
 */
package com.sinai.mshab.client.ui.aggregate;

import java.util.Iterator;

import com.google.gwt.user.client.ui.CellPanel;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.IndexedPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.sinai.mshab.client.ui.FormComponent;
import com.sinai.mshab.client.ui.label.DescriptionLabel;
import com.sinai.mshab.client.ui.label.ErrorLabel;

/**
 * <code>AggregateFormComponent</code> offers another layer between aggregate
 * components and {@link FormComponent}. This allows for the creation of
 * aggregate component specific methods that are enforced in all aggregate
 * components, without forcing the methods on basic components.
 * 
 * @author Arthur Kalmenson
 */
public abstract class AggregateFormComponent extends FormComponent implements
		HasWidgets, IndexedPanel {

	/**
	 * The {@link Panel} that contains all the widgets this
	 * AggregateFormComponent will contain.
	 */
	protected CellPanel panel;

	/**
	 * The description label of this AggregateFormComponent.
	 */
	private DescriptionLabel descriptionLabel;

	/**
	 * The error label of this AggregateFormComponent.
	 */
	private ErrorLabel errorLabel;

	/**
	 * Initializes this AggregateFormComponent's widget.
	 * 
	 * @param panel
	 *            the panel for this AggregateFormComponent.
	 */
	protected void initializeWidget(CellPanel panel) {
		this.panel = panel;
	}

	public abstract Object clone();

	public abstract void sendAnswer(DataReceiver receiver);

	/**
	 * Returns a printable version of this <code>AggregateFormComponent</code>.
	 * The {@link VerticalPanel} contains {@link HorizontalPanel}s aggregated
	 * from sub-components.
	 * 
	 * @return a printable version of this <code>AggregateFormComponent</code>.
	 */
	public abstract VerticalPanel toReport();

	/**
	 * Adds a description to this AggregateFormComponent. The description is a
	 * Label that is inserted into the first element of this
	 * AggregateFormComponent.
	 * 
	 * @param description
	 *            the description for this component.
	 */
	public void addDescription(String description) {

		// set the description text of FormComponent.
		this.description = description;

		// create the DescriptionLabel and add it to the panel.
		descriptionLabel = new DescriptionLabel(description);
		insertIntoPanel(descriptionLabel, 0);
	}

	/**
	 * Adds an error message to this AggregateFormComponent. The error message
	 * is inserted after the description, however, if there is no description
	 * present, the error message will be inserted as the first element.
	 * 
	 * @param errorMessage
	 *            the error message that will appear for this component.
	 */
	public void addErrorMessage(String errorMessage) {

		// set the error message of FormComponent
		this.error_msg = errorMessage;

		// create the ErrorLabel and add it to the panel. We normally add it to
		// index 1, however, if there is no descriptionLabel, we add it to index
		// 0.
		errorLabel = new ErrorLabel(errorMessage);
		int indexOfErrorLabel;
		if (descriptionLabel == null) {
			indexOfErrorLabel = 0;
		} else {
			indexOfErrorLabel = 1;
		}

		insertIntoPanel(errorLabel, indexOfErrorLabel);	
	}

	/**
	 * Inserts <code>widget</code> into the panel at <code>index</code>.
	 * 
	 * @param widget
	 *            the widget to insert.
	 * @param index
	 *            the index where to insert <code>widget</code>.
	 */
	private void insertIntoPanel(Widget widget, int index) {
		if (panel instanceof HorizontalPanel) {
			HorizontalPanel hpanel = (HorizontalPanel) panel;
			hpanel.insert(widget, index);
		} else if (panel instanceof VerticalPanel) {
			VerticalPanel vpanel = (VerticalPanel) panel;
			vpanel.insert(widget, index);
		}
	}

	// implement HasWidgets methods.

	public void add(Widget widget) {
		panel.add(widget);
	}

	public void clear() {
		panel.clear();
	}

	public Iterator iterator() {
		return panel.iterator();
	}

	public boolean remove(Widget widget) {
		return panel.remove(widget);
	}

	// implement IndexedPanel methods.
	public Widget getWidget(int index) {
		return panel.getWidget(index);
	}

	public int getWidgetCount() {
		return panel.getWidgetCount();
	}

	public int getWidgetIndex(Widget child) {
		return panel.getWidgetIndex(child);
	}

	public boolean remove(int index) {
		return panel.remove(index);
	}
}
